package battleship;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class Invite {
	final public static String NAME_ACCEPT = "accept";
	final public static String NAME_REJECT = "reject";
	final public static String NAME_CANCEL = "cancel";

	public static enum Column {
		uids, uidr
	};

	public static List<String[]> getCurrentGameInfo(HttpSession session)
			throws SQLException {
		final String pid = session.getAttribute(Constants.ATTR_UID).toString();
		final Connection con = Database.open();
		final PreparedStatement ps = con
				.prepareStatement("select gid, uid1, uid2, turn from Game where (uid1=binary ? or uid2=binary ?) and winner is NULL");
		ps.setString(1, pid);
		ps.setString(2, pid);

		final List<String[]> list = new ArrayList<String[]>();
		final ResultSet rs = ps.executeQuery();
		while (rs.next()) {
			final int gid = rs.getInt(1);
			final String opponent = rs
					.getString(pid.equals(rs.getString(2)) ? 3 : 2);
			final String turn = rs.getString(4);
			list.add(new String[] { String.valueOf(gid), opponent, turn });
		}
		Database.close(con);
		return list;
	}
	
	public static Map<String,String> getNicknames()
	throws SQLException {
		final Connection con = Database.open();
		final Map<String,String> nicknames = new HashMap<String,String>();
		final PreparedStatement ps = con
				.prepareStatement("select uid,nickname from User");
		final ResultSet rs = ps.executeQuery();
		while (rs.next()) {
			nicknames.put(rs.getString("uid"), rs.getString("nickname"));
		}
		Database.close(con);
		return nicknames;
	}

	public static Properties getFinishedGameInfo(HttpSession session)
			throws SQLException {
		final String pid = session.getAttribute(Constants.ATTR_UID).toString();
		final Connection con = Database.open();
		final PreparedStatement ps = con
				.prepareStatement("select gid, uid1, uid2 from Game where (uid1=binary ? or uid2=binary ?) and winner is not NULL");
		ps.setString(1, pid);
		ps.setString(2, pid);

		final Properties p = new Properties();
		final ResultSet rs = ps.executeQuery();
		while (rs.next()) {
			final String opponent = rs
					.getString(pid.equals(rs.getString(2)) ? 3 : 2);
			p.put(String.valueOf(rs.getInt(1)), opponent);
		}
		Database.close(con);
		return p;
	}

	@SuppressWarnings("unchecked")
	public static void processRequest(HttpServletRequest request)
			throws IOException, SQLException {
		final String myUid = request.getSession()
				.getAttribute(Constants.ATTR_UID).toString();
		final Enumeration<String> names = request.getParameterNames();
		final Connection con = Database.open();

		final String invitee = request.getParameter("invitee");
		if (invitee != null) {
			if (invitee.equals(myUid)) {
			} else {
				final PreparedStatement insert = con
						.prepareStatement("insert into Invite values(?,?)");
				if (invitee.equals(Constants.COMPUTER_UID)) {
					insert.setString(1, invitee);
					insert.setString(2, myUid);
				} else {
					insert.setString(1, myUid);
					insert.setString(2, invitee);
				}
				insert.executeUpdate();
			}
		}

		while (names.hasMoreElements()) {
			final String uid = names.nextElement();
			final String value = request.getParameter(uid);
			if (value.equals(NAME_ACCEPT)) {
				final PreparedStatement select = con
						.prepareStatement("select * from Invite where uids=binary ? and uidr=binary ?");
				select.setString(1, uid);
				select.setString(2, myUid);
				final ResultSet rs = select.executeQuery();
				if (rs.next()) {
					final PreparedStatement insert = con
							.prepareStatement("insert into Game(uid1,uid2,turn) values(?,?,?)");
					insert.setString(1, myUid);
					insert.setString(2, uid);
					insert.setString(3, myUid);
					insert.executeUpdate();

					// Get ID of the row that was just inserted
					final PreparedStatement selectId = con
							.prepareStatement("select max(gid) from Game");
					final ResultSet rsId = selectId.executeQuery();
					rsId.next();
					final int id = rsId.getInt(1);
					new Game(id, myUid, uid).serializeIfChanged();
				}
			}
			if (value.equals(NAME_ACCEPT) || value.equals(NAME_REJECT)) {
				final PreparedStatement delete = con
						.prepareStatement("delete from Invite where uids=binary ? and uidr=binary ?");
				delete.setString(1, uid);
				delete.setString(2, myUid);
				delete.executeUpdate();
			}
		}

		final String[] cancelUids = request.getParameterValues(NAME_CANCEL);
		if (cancelUids != null && cancelUids.length > 0) {
			for (final String uid : cancelUids) {
				final PreparedStatement delete = con
						.prepareStatement("delete from Invite where uids=binary ? and uidr=binary ?");
				delete.setString(1, myUid);
				delete.setString(2, uid);
				delete.executeUpdate();
			}
		}

		Database.close(con);
	}

	private static String[] getUids(Column c, String uid) throws SQLException {
		Column otherColumn = Column.values()[0];
		for (int i = 0; i < Column.values().length; i++) {
			if (c.equals(Column.values()[i])) {
				otherColumn = Column.values()[(i + 1) % Column.values().length];
			}
		}

		final Connection con = Database.open();
		final PreparedStatement ps = con
				.prepareStatement("select * from Invite where " + c.name()
						+ "=?");
		ps.setString(1, uid);
		final ResultSet rs = ps.executeQuery();
		rs.last();
		final String[] uids = new String[rs.getRow()];
		rs.beforeFirst();
		for (int i = 0; i < uids.length && rs.next(); i++) {
			uids[i] = rs.getString(otherColumn.name());
		}
		Database.close(con);
		return uids;
	}

	public static String[] getInviters(HttpSession session) throws SQLException {
		return getUids(Column.uidr, session.getAttribute(Constants.ATTR_UID)
				.toString());
	}

	public static String[] getInvitees(HttpSession session) throws SQLException {
		return getUids(Column.uids, session.getAttribute(Constants.ATTR_UID)
				.toString());
	}
}
